﻿using System.Text;
using System.Text.RegularExpressions;
using SixLabors.ImageSharp;

namespace SL651Center2.x
{
    public static class Helper
    {
        /// <summary>
        /// 将字节数组转成十六进制字符串
        /// </summary>
        /// <param name="_byte">要转换的字节数组</param>
        /// <returns>转换后的十六进制字符串</returns>
        public static string ToHEXString(params byte[] _byte)
        {
            StringBuilder builder = new StringBuilder();
            foreach (byte b in _byte)
            {
                builder.Append(string.Format("{0:X2}", b));
            }
            return builder.ToString().Trim();
        }
        /// <summary>
        /// 将字节数组转换为十六进制字符串
        /// </summary>
        /// <param name="_byte">要转换的只读字节跨度</param>
        /// <returns>转换后的十六进制字符串</returns>
        public static string ToHEXString(ReadOnlySpan<byte> _byte)
        {
            StringBuilder builder = new StringBuilder();
            foreach (byte b in _byte)
            {
                builder.Append(string.Format("{0:X2}", b));
            }
            return builder.ToString().Trim();
        }
        /// <summary>
        /// 将字节数组转换成十六进制字符串
        /// </summary>
        /// <param name="_byte">要转换的字节数组</param>
        /// <param name="count">要转换的字节长度</param>
        /// <returns>转换后的十六进制字符串</returns>
        public static string ToHEXString(byte[] _byte, int count)
        {
            if (count > _byte.Length)
            {
                return "";
            }
            StringBuilder builder = new StringBuilder();
            for (int i = 0; i < count; i++)
            {
                builder.Append(string.Format("{0:X2}", _byte[i]));
            }
            return builder.ToString().Trim();
        }
        /// <summary>
        /// 将字节数组转换成十六进制字符串
        /// </summary>
        /// <param name="_byte">要转换的字节数组</param>
        /// <param name="start">转换的开始位置</param>
        /// <param name="count">转换的长度</param>
        /// <returns>转换后的十六进制字符串</returns>
        public static string ToHEXString(byte[] _byte, int start, int count)
        {
            if (start > count)
            {
                return "";
            }
            StringBuilder builder = new StringBuilder();
            for (int i = start; i < count; i++)
            {
                builder.Append(string.Format("{0:X2}", _byte[i]));
            }
            return builder.ToString().Trim();
        }

        /// <summary>
        /// CRC16 算法 
        /// </summary>
        /// <param name="buffer">要计算的字节数组</param>
        /// <returns>计算得到的CRC16字节数组</returns>
        public static byte[] Crc16(byte[] buffer)
        {
            return Crc16(buffer, 0, buffer.Length);
        }
        /// <summary>
        /// CRC16 算法
        /// </summary>
        /// <param name="buffer">要计算的字节序列</param>
        /// <returns>计算得到的CRC16字节数组</returns>
        public static byte[] Crc16(ReadOnlySpan<byte> buffer)
        {
            return Crc16(buffer, 0, buffer.Length);
        }
        /// <summary>
        /// CRC16 算法
        /// </summary>
        /// <param name="buffer">要计算的字节数组</param>
        /// <param name="start">开始位置</param>
        /// <param name="len">计算长度</param>
        /// <returns></returns>
        public static byte[] Crc16(byte[] buffer, int start = 0, int len = 0)
        {
            if (buffer == null || buffer.Length == 0) return null;
            if (start < 0) return null;
            if (len == 0) len = buffer.Length - start;
            var length = start + len;
            if (length > buffer.Length) return null;
            ushort crc = 0xFFFF;// Initial value
            for (var i = start; i < length; i++)
            {
                crc ^= buffer[i];
                for (var j = 0; j < 8; j++)
                {
                    if ((crc & 1) != 0)
                        crc = (ushort)(crc >> 1 ^ 0xA001);// 0xA001 = reverse 0x8005
                    else
                        crc = (ushort)(crc >> 1);
                }
            }
            var ret = BitConverter.GetBytes(crc);
            Array.Reverse(ret);
            return ret;
        }
        /// <summary>
        /// CRC16算法
        /// </summary>
        /// <param name="buffer">要计算的字节序列</param>
        /// <param name="start">起始位置</param>
        /// <param name="len">计算长度</param>
        /// <returns>计算后的CRC16字节数组</returns>
        public static byte[] Crc16(ReadOnlySpan<byte> buffer, int start = 0, int len = 0)
        {
            if (buffer == null || buffer.Length == 0) return null;
            if (start < 0) return null;
            if (len == 0) len = buffer.Length - start;
            var length = start + len;
            if (length > buffer.Length) return null;
            ushort crc = 0xFFFF;// Initial value
            for (var i = start; i < length; i++)
            {
                crc ^= buffer[i];
                for (var j = 0; j < 8; j++)
                {
                    if ((crc & 1) != 0)
                        crc = (ushort)(crc >> 1 ^ 0xA001);// 0xA001 = reverse 0x8005
                    else
                        crc = (ushort)(crc >> 1);
                }
            }
            var ret = BitConverter.GetBytes(crc);
            Array.Reverse(ret);
            return ret;
        }

        /// <summary>
        /// 将十六进制字符串转换为ASCII字符串
        /// </summary>
        /// <param name="hex">十六进制字符串</param>
        /// <returns>转换后的ASCII字符</returns>
        public static string HEXToASCII(string hex)
        {
            //十六进制发送时，发送框数据进行十六进制数据正则校验
            if (!Regex.IsMatch(hex, "^[0-9A-Fa-f]+$"))
            {
                throw new ArgumentException("字符串格式错误",nameof(hex));
            }

            int value = Convert.ToInt32(hex, 16);
            string stringValue = char.ConvertFromUtf32(value);
            char charValue = (char)value;

            return stringValue;
        }
        /// <summary>
        /// 将十六进制字符数组转换成ASCII字符串
        /// </summary>
        /// <param name="hex">十六进制字符串</param>
        /// <returns>转换后的ASCII字符</returns>
        public static string HEXToASCII(string[] hex)
        {
            StringBuilder builder = new StringBuilder();
            foreach (string hexValue in hex)
            {
                int value = Convert.ToInt32(hexValue, 16);
                string stringValue = char.ConvertFromUtf32(value);
                char charValue = (char)value;

                builder.Append(stringValue);
            }
            return builder.ToString();
        }
        /// <summary>
        /// 将字节数组转换成ASCII字符串
        /// </summary>
        /// <param name="bytes">要转换的字节数组</param>
        /// <returns>转换后的ASCII字符串</returns>
        public static string ByteToASCII(byte[] bytes)
        {
            var s = BitConverter.ToString(bytes);
            var s1 = s.Split('-');
            return HEXToASCII(s1);
        }

        /// <summary>
        /// 将十六进制字符串转换为BCD十进制
        /// </summary>
        /// <param name="hex">要转换的十六进制</param>
        /// <returns>转换后的十进制数字</returns>
        public static int HEXToBCDInt(string hex)
        {
            //十六进制发送时，发送框数据进行十六进制数据正则校验
            if (!Regex.IsMatch(hex, "^[0-9A-Fa-f]+$"))
            {
                //throw new ArgumentException("字符串格式错误", nameof(hex));
                throw new FormatException("字符串格式错误");
            }

            var num = 0;
            foreach (var item in hex)
            {
                num = num * 10 + (item - '0');

            }
            return num;
        }

        /// <summary>
        /// 将字节数组转换为BCD码
        /// </summary>
        /// <param name="b">要转换的字节数组</param>
        /// <returns>转换后的十进制数字</returns>
        public static int ByteToBCDInt(params byte[] b)
        {
            var hex = ToHEXString(b);
            return HEXToBCDInt(hex);
        }

        /// <summary>
        /// 将字节数组转换为二进制字符串
        /// </summary>
        /// <param name="bytes">要转换的字节数组</param>
        /// <returns>转换后的二进制字符串</returns>
        public static string ByteToBinString(byte[] bytes)
        {
            StringBuilder str = new StringBuilder();
            foreach (var item in bytes)
            {
                var s = Convert.ToString(item, 2).PadLeft(8, '0');
                str.Append(s);
            }
            return str.ToString().Trim();
        }
        /// <summary>
        /// 将字节转换为8位二进制字符串
        /// </summary>
        /// <param name="b">要转换的字节</param>
        /// <returns>转换后的二进制字符串</returns>
        public static string ByteToBinString(byte b)
        {
            var s = Convert.ToString(b, 2).PadLeft(8, '0');
            return s.ToString().Trim();
        }

        /// <summary>
        /// 将字节数据转换成图片
        /// </summary>
        /// <param name="bytes">图片的字节数据</param>
        /// <returns>转换后的图片存储位置</returns>
        public static string ByteToImg(byte[] bytes, string name = "fileName.jpg")
        {
            if (!bytes.Any())
            {
                return "空数据";
            }
            string basePath = Path.Combine("img");
            string imgName = Path.Combine(basePath, name);
            if (!Directory.Exists(basePath))
            {
                Directory.CreateDirectory(basePath);
            }
            try
            {
                MemoryStream ms = new MemoryStream(bytes);
                Image image = Image.Load(ms);
                image.SaveAsJpeg(imgName);
                ms.Close();

                //Console.WriteLine(basePath);
                //Console.WriteLine(imgName);

                return imgName;
            }
            catch (Exception e)
            {
                //Console.WriteLine(e);
                return e.Message;
            }
        }

        /// <summary>
        /// 将十六进制字符串转换为字节数组
        /// </summary>
        /// <param name="hex">要转换的十六进制字符串</param>
        /// <returns>转换后的字节数组</returns>
        public static byte[] HEXStrToByte(string hex)
        {
            //十六进制发送时，发送框数据进行十六进制数据正则校验
            if (!Regex.IsMatch(hex, "^[0-9A-Fa-f]+$"))
            {
                throw new ArgumentException("字符串格式错误",nameof(hex));                
            }

            if (hex.Length % 2 != 0)
            {
                hex = "0" + hex;   //如果是奇数，前边直接补0
            }
            byte[] temp = new byte[hex.Length / 2];
            for (int i = 0; i < temp.Length; i++)
            {
                temp[i] = Convert.ToByte(hex.Substring(i * 2, 2), 16);
            }
            return temp;
        }

        /// <summary>
        /// 获取BDC格式的时间字节数组
        /// </summary>
        /// <param name="isHEX">返回的字节数组是HEX格式还是ASCII格式。true:返回HEX格式。false:返回ASCII格式</param>
        /// <param name="l">精度。默认获取到秒。值为5时获取到分；值为4时获取到小时</param>        
        /// <returns>BDC格式时间的字节数组</returns>
        public static byte[] GetBCDTimeBytes(bool isHEX = true, int l = 6)
        {
            var time = DateTime.Now;
            string yy = (time.Year % 100).ToString().PadLeft(2, '0');
            string MM = time.Month.ToString().PadLeft(2, '0');
            string dd = time.Day.ToString().PadLeft(2, '0');
            string hh = time.Hour.ToString().PadLeft(2, '0');
            string mm = time.Minute.ToString().PadLeft(2, '0');
            string ss = time.Second.ToString().PadLeft(2, '0');

            if (l == 4)
            {
                string time2 = $"{yy}{MM}{dd}{hh}";
                return isHEX ? HEXStrToByte(time2) : Encoding.ASCII.GetBytes(time2);
            }

            if (l == 5)
            {
                string time1 = $"{yy}{MM}{dd}{hh}{mm}";
                return isHEX ? HEXStrToByte(time1) : Encoding.ASCII.GetBytes(time1);
            }

            string time3 = $"{yy}{MM}{dd}{hh}{mm}{ss}";
            return isHEX ? HEXStrToByte(time3) : Encoding.ASCII.GetBytes(time3);
        }

        /// <summary>
        /// 将时间格式转换为BCD时间格式的字节数组
        /// </summary>
        /// <param name="time">要转换的时间</param>
        /// <param name="l">精度。默认获取到秒。值为5时获取到分；值为4时获取到小时</param>
        /// <param name="isHEX">返回的字节数组是HEX格式还是ASCII格式。true:返回HEX格式。false:返回ASCII格式</param>
        /// <returns></returns>
        public static byte[] DateTimeToBCDTimeBytes(DateTime time, int l = 6, bool isHEX = true)
        {
            string yy = (time.Year % 100).ToString().PadLeft(2, '0');
            string MM = time.Month.ToString().PadLeft(2, '0');
            string dd = time.Day.ToString().PadLeft(2, '0');
            string hh = time.Hour.ToString().PadLeft(2, '0');
            string mm = time.Minute.ToString().PadLeft(2, '0');
            string ss = time.Second.ToString().PadLeft(2, '0');

            if (l == 4)
            {
                string time2 = $"{yy}{MM}{dd}{hh}";
                return isHEX ? HEXStrToByte(time2) : Encoding.ASCII.GetBytes(time2);
            }

            if (l == 5)
            {
                string time1 = $"{yy}{MM}{dd}{hh}{mm}";
                return isHEX ? HEXStrToByte(time1) : Encoding.ASCII.GetBytes(time1);
            }

            string time3 = $"{yy}{MM}{dd}{hh}{mm}{ss}";
            return isHEX ? HEXStrToByte(time3) : Encoding.ASCII.GetBytes(time3);
        }

        /// <summary>
        /// 将BCD时间字节数组转换为时间字符串
        /// </summary>
        /// <param name="bytes">要转换的时间字节数组</param>
        /// <param name="b">报文格式，1 代表ASCII格式，2 代表HEX/BCD格式</param>
        /// <returns></returns>
        public static string ByteToBCDTime(byte[] bytes, byte b = 2)
        {
            if (b == 1)
            {
                var time = bytes.ToASCIIString();
                return StringToBCDTime(time);
            }
            var timeHEX = BitConverter.ToString(bytes);
            var timearr = timeHEX.Split('-');

            if (timearr.Length == 4)
            {
                return $"{timearr[0]}-{timearr[1]}-{timearr[2]} {timearr[3]}";
            }
            if (timearr.Length == 5)
            {
                return $"{timearr[0]}-{timearr[1]}-{timearr[2]} {timearr[3]}:{timearr[4]}";
            }
            return $"{timearr[0]}-{timearr[1]}-{timearr[2]} {timearr[3]}:{timearr[4]}:{timearr[5]}";
        }

        /// <summary>
        /// 将BDC时间码转换为时间字符串（yy-MM-dd HH:mm:ss）具体格式依据传入的字符串而定
        /// </summary>
        /// <param name="time">BCD格式的时间字符串</param>
        /// <returns>转换后的时间字符串</returns>
        public static string StringToBCDTime(string time)
        {
            if (time.Length == 8)
            {
                return $"{time[..2]}-{time.Substring(2, 2)}-{time.Substring(4, 2)} {time.Substring(6, 2)}";
            }
            if (time.Length == 10)
            {
                return $"{time[..2]}-{time.Substring(2, 2)}-{time.Substring(4, 2)} {time.Substring(6, 2)}:{time.Substring(8, 2)}";
            }
            return $"{time[..2]}-{time.Substring(2, 2)}-{time.Substring(4, 2)} {time.Substring(6, 2)}:{time.Substring(8, 2)}:{time.Substring(10, 2)}";

        }

        /// <summary>
        ///  把字符串按照指定长度分割
        /// </summary>
        /// <param name="txtString">要分割的字符串</param>
        /// <param name="charNumber">分割长度</param>
        /// <returns>分割后的字符串数组</returns>
        public static string[] GetSeparateSubString(string txtString, int charNumber)
        {
            List<string> arrlist = new List<string>();
            string tempStr = txtString;
            for (int i = 0; i < tempStr.Length; i += charNumber)
            {
                if (tempStr.Length - i > charNumber)//如果是，就截取
                {
                    arrlist.Add(tempStr.Substring(i, charNumber));
                }
                else
                {
                    arrlist.Add(tempStr.Substring(i));//如果不是，就截取最后剩下的那部分
                }
            }
            return arrlist.ToArray();
        }

        /// <summary>
        /// 获取要素的数据定义的字节数组
        /// </summary>
        /// <param name="ddl">要素的数据定义</param>
        /// <returns>数据定义字节数组</returns>
        public static byte[] GetDataDefinitionBytes((int, decimal) ddl)
        {
            //得到该要素的数据定义
            var (d, pre) = ddl;

            //高位
            var hi = Convert.ToString(d, 2).PadLeft(5, '0');

            //低位
            var l = pre.ToString();
            //计算0的个数，0的个数代表小数位数
            var ll = l.Count(i => "0".Contains(i));
            //得到二进制
            var lo = Convert.ToString(ll, 2).PadLeft(3, '0');

            //数据定义
            //组合高位和低位二进制
            var defb = string.Join("", hi, lo);
            //将二进制转换为十六机制
            var defh = string.Format("{0:X2}", Convert.ToInt16(defb, 2));
            //得到十六进制的字节数组
            var def = HEXStrToByte(defh);

            return def;
        }

    }
}
